// =============================================================
// CFactory/CService/CServiceProxy/CServiceContainer
// ---------------------------------------
// Author : Woo-Hyun Kim
// Email : woorung@icu.ac.kr or woorung@nhncorp.com
// Date : Aug. 24, 2007
// =============================================================
#include "CServiceProxy.h"

// static
long CServiceProxy::id = 0;

CServiceProxy::CServiceProxy()
{
        char tmp_name[32];
        sprintf(tmp_name,"ServiceProxy-%ld", id++);

        this->name = tmp_name;

	service_proxy = new CFactoryProxy();

	init();
}

CServiceProxy::CServiceProxy(char *name)
{
        setName(name);

	service_proxy = new CFactoryProxy();
	
	init();
}

CServiceProxy::~CServiceProxy()
{
	fin();

	// free memory related to user-defined data/classes
	soap_dealloc((struct soap *)service_proxy, NULL);
	soap_delete((struct soap *)service_proxy, NULL);

	// free memory related to serialization/deserialization
	soap_destroy((struct soap *)service_proxy);
	soap_end((struct soap *)service_proxy);

	// completely free soap structure
	//soap_free((struct soap *)service_proxy);
	soap_done((struct soap *)service_proxy);

	delete service_proxy;
}

void CServiceProxy::init()
{
	//soap_set_imode((struct soap *)service_proxy, SOAP_IO_KEEPALIVE);
	//soap_set_omode((struct soap *)service_proxy, SOAP_IO_KEEPALIVE);
}

void CServiceProxy::fin()
{
	//soap_clr_imode((struct soap *)service_proxy, SOAP_IO_KEEPALIVE);
	//soap_clr_omode((struct soap *)service_proxy, SOAP_IO_KEEPALIVE);
}

struct soap *CServiceProxy::soap()
{
	return (struct soap *)service_proxy;
}

void CServiceProxy::setName(char *name)
{
        this->name = name;
}

char *CServiceProxy::getName()
{
        return (char *)this->name.c_str();
}

int CServiceProxy::connect(char *host, int port)
{
	char tmp_url[256];
	sprintf(tmp_url, "http://%s:%d", host, port);
	
	url = tmp_url;

	service_proxy->soap_endpoint = (char *) url.c_str();
}

int CServiceProxy::gc()
{
	// free memory related to user-defined data/classes
	soap_dealloc((struct soap *)service_proxy, NULL);
	soap_delete((struct soap *)service_proxy, NULL);

	// free memory related to serialization/deserialization
	soap_destroy((struct soap *)service_proxy);
	soap_end((struct soap *)service_proxy);
}

int CServiceProxy::initialize(cube__CService *serviceid, int &res)
{
	return service_proxy->initialize(serviceid, res);
}

// service invoker 
int CServiceProxy::invoke(cube__CService *serviceid, cube__CObject *in, struct cube__invokeResponse &res)
{
	//return service_proxy->invoke(name, in, res);
	return service_proxy->invoke(serviceid, in, res);
}

int CServiceProxy::finalize(cube__CService *serviceid, int &res)
{
	return service_proxy->finalize(serviceid, res);
}

// keyval-based invoke
int CServiceProxy::invoke(char *servicename, map<string,string> &in, map<string,string> &out)
{
	int size = in.size();

	CObjectArray *pobjs = new CObjectArray(size);

	map<string,string>::iterator kv = in.begin();
	for(int i=0;kv!=in.end();) {
		pobjs->__ptr[i] = new cube__CKeyValue();
		dynamic_cast<cube__CKeyValue *>(pobjs->__ptr[i])->set((char *)kv->first.c_str(), (char *)kv->second.c_str());

		i++;
		kv++;
	}

	cube__CService serviceid;
	serviceid.service(servicename);
	//serviceid.instance(instancename);

	struct cube__invokeResponse res;

	int status = invoke(&serviceid, pobjs, res);

	for(int i=0;i<size;i++) delete (*pobjs)[i];
	delete pobjs;

	if(status!=SOAP_OK) soap_print_fault(this->soap(), stderr);
	else {
		pobjs = dynamic_cast<CObjectArray *>(res.out);
		if(pobjs==NULL) {
			cerr << "ERROR : output type is not array" << endl;
			return -1;
		}
		
		for(int i=0;i<pobjs->__size;i++) {
			cube__CKeyValue *keyval= dynamic_cast<cube__CKeyValue *>(pobjs->__ptr[i]);
			if(keyval==NULL) {
				cerr << "ERROR : array must have (key,value) pairs" << endl;
				break;
			}

			out[keyval->getKey()] = keyval->getValue();
		}
	}

	return status;
}
